home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 September / Macworld (1998-09).dmg / Shareware World / Info / For Developers / MacZoop 1.8.3 / More Classes / Window Classes / ZScroller.cpp < prev    next >
Text File  |  1998-07-08  |  26KB  |  1,063 lines

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            MacZoop - "the framework for the rest of us"         
  5. *
  6. *
  7. *
  8. *            ZScroller.cpp        -- a window with scrollbars
  9. *
  10. *
  11. *
  12. *
  13. *
  14. *            © 1996, Graham Cox
  15. *
  16. *
  17. *
  18. *
  19. *************************************************************************************************/
  20.  
  21.  
  22. #include    "ZScroller.h"
  23. #include    "ZGrafState.h"
  24. #include    "MacZoop.h"
  25.  
  26.  
  27. static pascal void     ScrollBarZProc( ControlHandle theControl, short partCode );
  28. static pascal void    ThumbZProc();
  29.  
  30. static ControlActionUPP        gScrollbarProc = NewControlActionProc( ScrollBarZProc );
  31. static ControlHandle        gCurrentScrollbar = NULL;
  32.  
  33. #ifdef _LIVE_SCROLLING
  34. static ThumbActionUPP        gThumbProc = NewThumbActionProc( ThumbZProc );
  35. #endif
  36.  
  37.  
  38. CLASSCONSTRUCTOR( ZScroller );
  39.  
  40. /*--------------------------------***  CONSTRUCTOR  ***---------------------------------*/
  41.  
  42. ZScroller::ZScroller(    ZCommander* aBoss,
  43.                         const short windID,
  44.                         const Boolean hasHScroll,
  45.                         const Boolean hasVScroll )
  46.     : ZWindow( aBoss, windID )
  47. {
  48.     classID = CLASS_ZScroller;
  49.     
  50.     theHBar = NULL;
  51.     theVBar = NULL;
  52.     SetRect( &bounds, 0, 0, 0, 0 );
  53.     hScale = 10;
  54.     vScale = 10;
  55.     
  56.     hasHBar = hasHScroll;
  57.     hasVBar = hasVScroll;
  58.     
  59.     cInitValue = 0;
  60. }
  61.  
  62.  
  63. ZScroller::ZScroller()
  64.     : ZWindow()
  65. {
  66.     classID = CLASS_ZScroller;
  67.     
  68.     theHBar = NULL;
  69.     theVBar = NULL;
  70.     SetRect( &bounds, 0, 0, 0, 0 );
  71.     hScale = 10;
  72.     vScale = 10;
  73.     
  74.     hasHBar = FALSE;
  75.     hasVBar = FALSE;
  76.     
  77.     cInitValue = 0;
  78. }
  79.  
  80.  
  81. /*--------------------------------***  INITZWINDOW  ***---------------------------------*/
  82. /*    
  83.  
  84. overrides the base ZWindow to initialise the scrollbars as well
  85.  
  86. ----------------------------------------------------------------------------------------*/
  87.  
  88. void    ZScroller::InitZWindow()
  89. {
  90.     ZWindow::InitZWindow();        // do the basic initialisation
  91.     
  92.     Focus();
  93.     MakeScrollbars();            // make the scrollbar controls
  94.     
  95.     // set size to arbitrary small size- first call to SetBounds will set it up.
  96.     
  97.     SetRect( &sizeRect, 120, 90, 120, 90 );
  98.     
  99.     // in case there is special scrollbar positioning, call MoveScrollbars:
  100.     
  101.     MoveScrollbars();
  102. }
  103.  
  104.  
  105.  
  106. /*----------------------------------***  ACTIVATE  ***----------------------------------*/
  107. /*    
  108.  
  109. overrides ZWindow to show the scrollbars when the window state changes
  110.  
  111. ----------------------------------------------------------------------------------------*/
  112.  
  113. void    ZScroller::Activate()
  114. {
  115.     ZWindow::Activate();
  116.     
  117.     if ( hasVBar )
  118.         ShowControl( theVBar );
  119.         
  120.     if ( hasHBar )
  121.         ShowControl( theHBar );
  122. }
  123.  
  124.  
  125. /*---------------------------------***  DEACTIVATE  ***---------------------------------*/
  126. /*    
  127.  
  128. overrides ZWindow to hide the scrollbars when the window state changes
  129.  
  130. ----------------------------------------------------------------------------------------*/
  131.  
  132.  
  133. void    ZScroller::Deactivate()
  134. {
  135.     if ( hasVBar )
  136.         HideControl( theVBar );
  137.         
  138.     if ( hasHBar )
  139.         HideControl( theHBar );
  140.     
  141.     ZWindow::Deactivate();
  142. }
  143.  
  144.  
  145.  
  146. /*------------------------------------***  DRAW  ***------------------------------------*/
  147. /*    
  148.  
  149. overrides ZWindow to draw the content allowing for the scroll and the scrollbars themselves
  150.  
  151. ----------------------------------------------------------------------------------------*/
  152.  
  153. void    ZScroller::Draw()
  154. {
  155.     // need to set the origin to the scroll position here
  156.     
  157.     SetOriginToScroll();
  158.     
  159.     DrawContent();
  160.     
  161.     SetOrigin( 0, 0 );
  162.     ClipRect( &macWindow->portRect );        
  163.     UpdateControls( macWindow, macWindow->visRgn );
  164.     
  165.     DrawGrow();
  166. }
  167.  
  168.  
  169. /*----------------------------------***  DRAWGROW  ***----------------------------------*/
  170. /*    
  171.  
  172. overrides ZWindow to draw the grow box, allowing for the actual scrollbars present
  173.  
  174. ----------------------------------------------------------------------------------------*/
  175.  
  176.  
  177. void    ZScroller::DrawGrow()
  178. {
  179.     // overrides the standard method to clip down to the growbox. This prevents
  180.     // scrollbar lines being drawn when there are no scrollbars in one dimension
  181.  
  182.     Rect    growBoxRect = macWindow->portRect;
  183.     
  184.     if (! hasVBar )
  185.         growBoxRect.top = growBoxRect.bottom - kStdScrollbarWidth;
  186.         
  187.     if (! hasHBar )
  188.         growBoxRect.left = growBoxRect.right - kStdScrollbarWidth;
  189.         
  190.     ClipRect( &growBoxRect );
  191.     DrawGrowIcon( macWindow );
  192. }
  193.  
  194.  
  195.  
  196. /*------------------------------------***  CLICK  ***-----------------------------------*/
  197. /*    
  198.  
  199. overrides ZWindow to handle clicks in the scrollbars and perform the scrolling
  200.  
  201. ----------------------------------------------------------------------------------------*/
  202.  
  203. void    ZScroller::Click( const Point mouse, const short modifiers )
  204. {
  205.     // handle a click in the content and also the scrollbar clicks
  206.     
  207.     short            partCode, curValue;
  208.     ControlHandle    hitCtl;
  209.     Point            soMouse = mouse;
  210.     
  211.     // did the mouse go down in any part of a control (scrollbar)?
  212.     
  213.     partCode = FindControl( mouse, macWindow, &hitCtl );
  214.     
  215.     if ( partCode == kControlNoPart )
  216.     {
  217.         // translate the point to the current scroll offset
  218.         // before passing it to ClickContent.
  219.  
  220.         if ( hasHBar )
  221.             soMouse.h += GetControlValue( theHBar );
  222.             
  223.         if ( hasVBar )
  224.             soMouse.v += GetControlValue( theVBar );
  225.  
  226.         // set origin & clip to visible content area
  227.  
  228.         SetOriginToScroll();
  229.         ClickContent( soMouse, modifiers );
  230.     }
  231.     else
  232.     {
  233.         // scrollbar was hit, so track the control
  234.         
  235.         gCurrentScrollbar = hitCtl;
  236.         
  237.         curValue = GetControlValue( hitCtl );
  238.         
  239.         if ( partCode == kControlIndicatorPart )
  240.         {
  241.             #ifdef _LIVE_SCROLLING
  242.             cInitValue = GetControlValue( hitCtl );
  243.             partCode = TrackControl( hitCtl, mouse, (ControlActionUPP) gThumbProc );
  244.             #else
  245.             partCode = TrackControl( hitCtl, mouse, NULL );
  246.             #endif
  247.         }
  248.         else
  249.             partCode = TrackControl( hitCtl, mouse, gScrollbarProc );
  250.         
  251.         // if the thumb was dragged, figure out where it was dragged to and scroll
  252.         // the contents appropriately
  253.         
  254.         if ( partCode == kControlIndicatorPart )
  255.         {
  256.             #ifndef _LIVE_SCROLLING
  257.             curValue -= GetControlValue( hitCtl );
  258.             
  259.             if ( hitCtl == theHBar )
  260.                 Scroll( curValue, 0 );
  261.             else
  262.                 Scroll( 0, curValue );
  263.             #else
  264.             // after live scrolling, redraw the control so that the thumb hilite is cancelled
  265.             ClipRect( &macWindow->portRect );
  266.             Draw1Control( hitCtl );
  267.             SetOriginToScroll();
  268.             #endif
  269.  
  270.             PostScroll( hitCtl );
  271.             
  272.         }
  273.         gCurrentScrollbar = NULL;
  274.     }
  275. }
  276.  
  277.  
  278. /*-----------------------------------***  SETSIZE  ***----------------------------------*/
  279. /*    
  280.  
  281. overrides ZWindow to reposition the scrollbars when the window size is changed
  282. ----------------------------------------------------------------------------------------*/
  283.  
  284. void    ZScroller::SetSize( const short width, const short height, const Boolean reDraw )
  285. {
  286.     Focus();
  287.     
  288.     // if the reDraw flag is TRUE, we supress the various updates that would otherwise
  289.     // occur since we force the entire contents to reDraw in one go at the end. If reDraw
  290.     // is false, the normal updates are generated so that the relevant parts of the
  291.     // window are refreshed after the resize.
  292.     
  293.     HideScrollbars( reDraw );
  294.         
  295.     // need to erase the grow icon before sizing
  296.     
  297.     Rect    growRect = macWindow->portRect;
  298.     
  299.     growRect.left = growRect.right - kStdScrollbarWidth;
  300.     growRect.top = growRect.bottom - kStdScrollbarWidth;
  301.     EraseRect( &growRect );
  302.     
  303.     if ( ! reDraw )
  304.         InvalRect( &growRect );
  305.     
  306.     ZWindow::SetSize( width, height, !reDraw );
  307.     
  308.     MoveScrollbars();
  309.  
  310.     if ( reDraw )
  311.         Draw();
  312. }
  313.  
  314.  
  315.  
  316. /*------------------------------------***  ZOOM  ***------------------------------------*/
  317. /*    
  318.  
  319. overrides ZWindow to reposition the scrollbars when the window is zoomed
  320.  
  321. ----------------------------------------------------------------------------------------*/
  322.  
  323. void    ZScroller::Zoom( const short partCode )
  324. {
  325.     Focus();
  326.     
  327.     HideScrollbars( FALSE );
  328.     
  329.     ZWindow::Zoom( partCode );
  330.  
  331.     MoveScrollbars();
  332.     Draw();
  333.     ValidRect( &macWindow->portRect );
  334. }
  335.  
  336.  
  337. /*----------------------------------***  SETBOUNDS  ***---------------------------------*/
  338. /*    
  339.  
  340. sets the scrollable area to a certain size. This then recalculates the scrollbar settings
  341. so that that area can be scrolled over. The bounds is the "real" size of a document.
  342.  
  343. ----------------------------------------------------------------------------------------*/
  344.  
  345.  
  346. void    ZScroller::SetBounds( const Rect& aBounds)
  347. {
  348.     bounds = aBounds;
  349.     CalculateControlParams();
  350.     
  351.     // by default, set the sizeRect for the window to the bounds
  352.     // plus the scrollbar widths, unless size rect is already bigger.
  353.     
  354.     Rect    sz = sizeRect;
  355.     
  356.     if ( hasHBar )
  357.         sz.bottom = MAX( sz.top, MAX( sz.bottom, ( bounds.bottom - bounds.top ) + kStdScrollbarWidth ));
  358.         
  359.     if ( hasVBar )
  360.         sz.right = MAX( sz.left, MAX( sz.right, ( bounds.right - bounds.left ) + kStdScrollbarWidth ));
  361.     
  362.     SetSizeRect( sz );
  363. }
  364.  
  365.  
  366. /*----------------------------------***  SETBOUNDS  ***---------------------------------*/
  367.  
  368.  
  369. void    ZScroller::SetBounds( short top, short left, short bottom, short right )
  370. {
  371.     Rect    r;
  372.     
  373.     SetRect( &r, left, top, right, bottom );
  374.     SetBounds( r );
  375. }
  376.  
  377.  
  378. /*----------------------------------***  SETBOUNDS  ***---------------------------------*/
  379.  
  380.  
  381. void    ZScroller::SetBounds( Point tl, Point br )
  382. {
  383.     Rect    r;
  384.     
  385.     Pt2Rect( tl, br, &r );
  386.     SetBounds( r );
  387. }
  388.  
  389.  
  390. /*---------------------------------***  GETBOUNDS  ***----------------------------------*/
  391. /*    
  392.  
  393. get the scrollable area
  394.  
  395. ----------------------------------------------------------------------------------------*/
  396.  
  397. void    ZScroller::GetBounds( Rect* aBounds )
  398. {
  399.     *aBounds = bounds;
  400. }
  401.  
  402.  
  403. /*--------------------------***  GETIDEALWINDOWZOOMSIZE  ***----------------------------*/
  404. /*    
  405. return the optimum ideal size for a zoomed window. By default this is equal to the
  406. max size rectangle, but you can override this if you know better.
  407. ----------------------------------------------------------------------------------------*/
  408.  
  409. void    ZScroller::GetIdealWindowZoomSize( Rect* idealSize )
  410. {
  411.     *idealSize = bounds;
  412.     
  413.     if ( EmptyRect( &bounds ))
  414.         GetContentRect( idealSize );
  415.     
  416.     idealSize->right += hasVBar? kStdScrollbarWidth : 0;
  417.     idealSize->bottom += hasHBar? kStdScrollbarWidth : 0;    
  418. }
  419.  
  420. /*------------------------------***  SETSCROLLAMOUNT  ***-------------------------------*/
  421. /*    
  422.  
  423. sets how many pixels each click on a scroll arrow shifts the content area
  424.  
  425. ----------------------------------------------------------------------------------------*/
  426.  
  427. void    ZScroller::SetScrollAmount( const short hAmount, const short vAmount )
  428. {
  429.     hScale = hAmount;
  430.     vScale = vAmount;
  431. }
  432.  
  433.  
  434. /*--------------------------------***  GETPOSITION  ***---------------------------------*/
  435. /*    
  436.  
  437. returns the current scroll position of the window- i.e. the "frame" position relative to
  438. the "real" document area (the bounds)
  439.  
  440. ----------------------------------------------------------------------------------------*/
  441.  
  442.  
  443. void    ZScroller::GetPosition( short* hPosition, short* vPosition )
  444. {
  445.     if ( hasVBar )
  446.         *vPosition = GetControlValue( theVBar );
  447.     else
  448.         *vPosition = 0;
  449.         
  450.     if ( hasHBar )
  451.         *hPosition = GetControlValue( theHBar );
  452.     else
  453.         *hPosition = 0;
  454. }
  455.  
  456.  
  457.  
  458. /*----------------------------------***  SCROLLTO  ***----------------------------------*/
  459. /*    
  460.  
  461. moves the content area to the scroll position passed. This immediately redraws the content
  462.  
  463. ----------------------------------------------------------------------------------------*/
  464.  
  465. void    ZScroller::ScrollTo( const short hPosition, const short vPosition )
  466. {
  467.     Rect    content;
  468.     short    fH, fV, pH, pV;
  469.     
  470.     GetPosition( &fH, &fV );
  471.     Focus();
  472.     
  473.     if ( hasHBar && ( GetControlMaximum( theHBar ) > GetControlMinimum( theHBar )))
  474.         SetControlValue( theHBar, hPosition );
  475.         
  476.     if ( hasVBar && ( GetControlMaximum( theVBar ) > GetControlMinimum( theVBar )))
  477.         SetControlValue( theVBar, vPosition );
  478.     
  479.     GetPosition( &pH, &pV );
  480.     Scroll( fH - pH, fV - pV );
  481.     
  482.     GetContentRect( &content );
  483.     SetOriginToScroll();
  484. }
  485.  
  486.  
  487. /*---------------------------------***  AUTOSCROLL  ***---------------------------------*/
  488. /*    
  489. if the mouse point passed is outside the content rect, the view is scrolled accordingly.
  490. This can be called from within some kind of drag loop if desired.
  491. ----------------------------------------------------------------------------------------*/
  492.  
  493. Boolean    ZScroller::AutoScroll( Point mousePt )
  494. {
  495.     Rect            cr;
  496.     Boolean            result = FALSE;
  497.     
  498.     GetContentRect( &cr );
  499.     
  500.     if ( ! PtInRect( mousePt, &cr ))
  501.     {
  502.         // mouse moved outside content, so figure out which way and
  503.         // scroll it accordingly.
  504.     
  505.         short dH = 0, dV = 0, maxScrollH, maxScrollV, pH, pV;
  506.         
  507.         maxScrollH = hScale * 4;
  508.         maxScrollV = vScale * 4;
  509.         
  510.         if ( mousePt.h > cr.right )
  511.             dH = MIN( maxScrollH, mousePt.h - cr.right );
  512.         else
  513.         {
  514.             if ( mousePt.h < cr.left )
  515.                 dH = MAX( -maxScrollH, mousePt.h - cr.left );
  516.         }
  517.             
  518.         if ( mousePt.v > cr.bottom )
  519.             dV = MIN( maxScrollV, mousePt.v - cr.bottom );
  520.         else
  521.         {
  522.             if ( mousePt.v < cr.top )
  523.                 dV = MAX( -maxScrollV, mousePt.v - cr.top );
  524.         }
  525.         
  526.         GetPosition( &pH, &pV );    
  527.         ScrollTo( pH + dH, pV + dV );
  528.         
  529.         GetPosition( &dH, &dV );
  530.         result = (( dH != pH ) || ( dV != pV ));
  531.     }
  532.     
  533.     return result;
  534. }
  535.  
  536.  
  537.  
  538.  
  539. /*-------------------------------***  GETCONTENTRECT  ***-------------------------------*/
  540. /*    
  541.  
  542. get the scrollable portion of the window- the bit you can see, less the scrollbars.
  543.  
  544. ----------------------------------------------------------------------------------------*/
  545.  
  546. void    ZScroller::GetContentRect( Rect* aRect )
  547. {
  548.     // returns the scrollable part of the window. The bit without the scrollbars.
  549.  
  550.     *aRect = macWindow->portRect;
  551.     if ( hasVBar )
  552.         aRect->right -= kStdScrollbarWidth;
  553.         
  554.     if ( hasHBar )
  555.         aRect->bottom -= kStdScrollbarWidth;
  556. }
  557.  
  558.  
  559.  
  560. /*---------------------------***  CALCULATECONTROLPARAMS  ***---------------------------*/
  561. /*    
  562.  
  563. sets the scrollbar maximums to correctly scroll the scrollarea. This is called when the
  564. bounds or the window frame area changes.
  565.  
  566. ----------------------------------------------------------------------------------------*/
  567.  
  568. void    ZScroller::CalculateControlParams()
  569. {
  570.     // this sets the maximums of the scrollbar to the difference between the content rect and
  571.     // the bounds.
  572.     
  573.     Rect    content;
  574.     short    hMax,vMax;
  575.     
  576.     SetOrigin( 0, 0 );
  577.     ClipRect( &macWindow->portRect );
  578.     
  579.     GetContentRect( &content );
  580.     
  581.     hMax = bounds.right  - ( content.right - content.left );
  582.     vMax = bounds.bottom - ( content.bottom - content.top );
  583.     
  584.     if ( hMax < 0 )
  585.         hMax = 0;
  586.         
  587.     if ( vMax < 0 )
  588.         vMax = 0;
  589.  
  590.     if ( hasHBar )
  591.     {
  592.         SetControlMaximum( theHBar, hMax );
  593.         SetControlMinimum( theHBar, bounds.left );
  594.     }
  595.         
  596.     if ( hasVBar )
  597.     {
  598.         SetControlMaximum( theVBar, vMax );
  599.         SetControlMinimum( theVBar, bounds.top );
  600.     }
  601. }
  602.  
  603.  
  604.  
  605. /*-------------------------------***  MAKESCROLLBARS  ***-------------------------------*/
  606. /*    
  607.  
  608. creates the scrollbars as part of the initialisation
  609.  
  610. ----------------------------------------------------------------------------------------*/
  611.  
  612. void    ZScroller::MakeScrollbars()
  613. {
  614.     // create the scrollbar controls initially. This is done by calling NewControl. We
  615.     // figure out the control rects from the window portrect.
  616.     
  617.     Rect    barRect;
  618.     Rect    wPortRect;
  619.     
  620.     wPortRect = macWindow->portRect;
  621.     
  622.     if ( hasHBar )
  623.     {
  624.         barRect = wPortRect;
  625.         barRect.right -= kStdScrollbarWidth - 1;
  626.         barRect.top = barRect.bottom - kStdScrollbarWidth - 1;
  627.         barRect.left -= 1;
  628.         OffsetRect(&barRect,0,1);
  629.         
  630.         FailNIL( theHBar = NewControl( macWindow, &barRect, NULL, FALSE, 0, 0, 0, scrollBarProc, (long) this));
  631.     
  632.         SetControlReference( theHBar, (long) this );
  633.     }
  634.     
  635.     if ( hasVBar )
  636.     {
  637.         barRect = wPortRect;
  638.         barRect.bottom -= kStdScrollbarWidth - 1;
  639.         barRect.left = barRect.right - kStdScrollbarWidth - 1;
  640.         barRect.top -= 1;
  641.         OffsetRect( &barRect, 1, 0 );
  642.  
  643.         FailNIL(theVBar = NewControl( macWindow, &barRect, NULL, FALSE, 0, 0, 0, scrollBarProc, (long) this));
  644.         
  645.         SetControlReference( theVBar, (long) this );
  646.     }
  647. }
  648.  
  649.  
  650.  
  651. /*-------------------------------***  MOVESCROLLBARS  ***-------------------------------*/
  652. /*    
  653.  
  654. moves the scrollbars to the edges of the window. Called when the window frame size changes.
  655. The scrollbars should generally be hidden before this operation. This then reshows them if
  656. the window is active, and recomputes the max values. If the scroll position is forced to
  657. change as a result, this redraws the content in the correct position.
  658.  
  659. ----------------------------------------------------------------------------------------*/
  660.  
  661. void    ZScroller::MoveScrollbars()
  662. {
  663.     // move the scrollbars after the window size has changed. They should be hidden beforehand
  664.     // and then shown afterwards. This will only show them if the window is active.
  665.     
  666.     Rect        wPortRect;
  667.     short        w,h,hVal = 0,vVal = 0;
  668.     Boolean        isActive;
  669.     
  670.     wPortRect = macWindow->portRect;
  671.     isActive = IsActive();
  672.     
  673.     if ( hasHBar )
  674.     {
  675.         hVal = GetControlValue( theHBar );
  676.  
  677.         w = wPortRect.right - wPortRect.left - kStdScrollbarWidth + 2;
  678.         h = kStdScrollbarWidth + 1;
  679.         
  680.         SizeControl( theHBar, w, h );
  681.         MoveControl( theHBar, wPortRect.left - 1, wPortRect.bottom - kStdScrollbarWidth );
  682.         
  683.         if ( isActive )
  684.             ShowControl( theHBar );
  685.         
  686.         ValidRect(&(*theHBar)->contrlRect);
  687.     }
  688.     
  689.     if ( hasVBar )
  690.     {
  691.         vVal = GetControlValue( theVBar );
  692.         
  693.         h = wPortRect.bottom - wPortRect.top - kStdScrollbarWidth + 2;
  694.         w = kStdScrollbarWidth + 1;
  695.         
  696.         SizeControl(theVBar, w, h );
  697.         MoveControl(theVBar, wPortRect.right - kStdScrollbarWidth,  wPortRect.top - 1 );
  698.         
  699.         if ( isActive )
  700.             ShowControl( theVBar );
  701.             
  702.         ValidRect(&(*theVBar)->contrlRect);
  703.     }
  704.     
  705.     CalculateControlParams();    // recompute maximums
  706.     
  707.     if ( hasVBar )
  708.         vVal -= GetControlValue( theVBar );
  709.         
  710.     if ( hasHBar )
  711.         hVal -= GetControlValue( theHBar );
  712.     
  713.     // if the value of the control changed as a result of altering the maximum, we need to
  714.     // ensure that the contents are scrolled to the right place.
  715.         
  716.     if ( hVal || vVal )
  717.     {
  718.         GetContentRect( &wPortRect );
  719.         EraseRect( &wPortRect );
  720.     }
  721. }
  722.  
  723.  
  724. /*-------------------------------***  HIDESCROLLBARS  ***-------------------------------*/
  725. /*    
  726. hides the scrollbars prior to performing a resize, etc. If you have a special arrangement
  727. in your window (e.g. an info panel in the scrollbar area) you can override this to get
  728. informed when you need to erase such areas, etc.
  729. ----------------------------------------------------------------------------------------*/
  730.  
  731. void    ZScroller::HideScrollbars( Boolean validateArea )
  732. {
  733.     if ( hasVBar )
  734.     {
  735.         HideControl( theVBar );
  736.         
  737.         if ( validateArea )
  738.             ValidRect(&(*theVBar)->contrlRect );
  739.     }
  740.         
  741.     if ( hasHBar )
  742.     {
  743.         HideControl( theHBar );
  744.         
  745.         if ( validateArea )
  746.             ValidRect(&(*theHBar)->contrlRect );
  747.     }
  748. }
  749.  
  750.  
  751.  
  752. /*---------------------------------***  POSTSCROLL  ***---------------------------------*/
  753. /*    
  754.  
  755. You can override this if you are interested in getting called after the thumb of a
  756. scrollbar was dragged.
  757.  
  758. ----------------------------------------------------------------------------------------*/
  759.  
  760. void    ZScroller::PostScroll( ControlHandle aCtl )
  761. {
  762. }
  763.  
  764.  
  765. /*------------------------------------***  SCROLL  ***----------------------------------*/
  766. /*    
  767.  
  768. shifts the content by dH and dV, updating the revealed area. This is called by the scroll
  769. bar callback function to implement continous scrolling.
  770.  
  771. ----------------------------------------------------------------------------------------*/
  772.  
  773. void    ZScroller::Scroll( const short dH, const short dV )
  774. {
  775.     // scrolls the content rect. This calls scrollrect to move the majority of the
  776.     // pixels, then calls DrawContent to fill in the rest.
  777.     
  778.     RgnHandle    updateRgn,saveClip;
  779.     Rect        content;
  780.     short        fH,fV;
  781.     
  782.     if ( dH == 0 && dV == 0 )
  783.         return;
  784.     
  785.     GetContentRect( &content );
  786.     updateRgn = NewRgn();
  787.     
  788.     GetClip( saveClip = NewRgn());
  789.     ScrollRect( &content, dH, dV, updateRgn );
  790.     
  791.     // need to set the origin of the view to the new location
  792.     
  793.     SetOriginToScroll();
  794.     
  795.     // offset the update region to allow for the origin
  796.     
  797.     GetPosition( &fH, &fV );
  798.     OffsetRgn( updateRgn, fH, fV );
  799.     SetClip( updateRgn );
  800.     
  801.     // draw the update region
  802.     
  803.     DrawContent();
  804.     
  805.     // restore the zero origin
  806.     
  807.     SetOrigin( 0, 0 );
  808.     SetClip( saveClip );
  809.     
  810.     DisposeRgn( saveClip );
  811.     DisposeRgn( updateRgn );
  812. }
  813.  
  814.  
  815. /*-----------------------------***  SETORIGINTOSCROLL  ***------------------------------*/
  816. /*    
  817.  
  818. sets the origin of the grafport to the correct scroll position. This is done to ensure
  819. that the contents get drawn in the right place regardless of where they are scrolled to.
  820.  
  821. ----------------------------------------------------------------------------------------*/
  822.  
  823. void    ZScroller::SetOriginToScroll()
  824. {
  825.     Rect    content;
  826.     short     vOrigin;
  827.     short     hOrigin;
  828.     
  829.     hOrigin = 0;
  830.     vOrigin = 0;
  831.  
  832.     if ( hasVBar )
  833.         vOrigin = GetControlValue( theVBar );
  834.         
  835.     if ( hasHBar )
  836.         hOrigin = GetControlValue( theHBar );
  837.         
  838.     SetOrigin( hOrigin, vOrigin );
  839.     
  840.     GetContentRect( &content );
  841.     ClipRect( &content );
  842. }
  843.  
  844.  
  845. /*-------------------------------***  SCROLLHANDLER  ***--------------------------------*/
  846. /*    
  847.  
  848. scrollbar callback function actually changes the scrollbar value as scrolling progresses
  849. and scrolls the content accordingly.
  850.  
  851. ----------------------------------------------------------------------------------------*/
  852.  
  853. void    ZScroller::ScrollHandler( const ControlHandle aCtl, const short partCode )
  854. {
  855.     // this actually peforms the scroll of the content rect
  856.     
  857.     short        curValue,page;
  858.     Boolean        hitIsVertical;
  859.     Rect        content;
  860.     RgnHandle    saveClip = NewRgn();
  861.     
  862.     curValue = GetControlValue( aCtl );
  863.     GetClip( saveClip );
  864.     
  865.     // are we scrolling the horizontal or the vertical bar? Find out by comparing
  866.     // the control with one of our data members
  867.     
  868.     hitIsVertical = ( aCtl == theVBar );
  869.     
  870.     // calculate the page amount. This is the height or width of the window less one
  871.     // scale amount.
  872.         
  873.     GetContentRect( &content );
  874.     
  875.     if ( hitIsVertical )
  876.         page = content.bottom - content.top - vScale;
  877.     else
  878.         page = content.right - content.left - hScale;     
  879.     
  880.     switch ( partCode )
  881.     {
  882.         case kControlUpButtonPart:
  883.             SetControlValue( aCtl, GetControlValue(aCtl) - (hitIsVertical? vScale : hScale ));
  884.             break;
  885.         case kControlDownButtonPart:
  886.             SetControlValue( aCtl, GetControlValue(aCtl) + (hitIsVertical? vScale : hScale ));
  887.             break;
  888.         case kControlPageUpPart:
  889.             SetControlValue( aCtl, GetControlValue(aCtl) - page );
  890.             break;
  891.         case kControlPageDownPart:
  892.             SetControlValue( aCtl, GetControlValue(aCtl) + page );
  893.             break;
  894.         case kControlIndicatorPart:
  895.             // called when live scrolling the thumb. Here we need to calculate where the mouse
  896.             // is and figure out what the correct control value would be. If the mouse goes outside the
  897.             // control too far, the control "springs back" to its previous value, stored in cInitValue.
  898.             // we have to keep control here until the mouse is released otherwise the alterations to
  899.             // the control value cause problems for the thumb dragging default behaviour if we allow
  900.             // control back every time we are called. Yet another annoying toolbox anomaly...
  901.             
  902.             #ifdef _LIVE_SCROLLING
  903.             
  904.             Rect    cr, slopR;
  905.             long    cRange, cVal;
  906.             Point    curMouse, lastMouse;
  907.             
  908.             GetMouse( &lastMouse );
  909.             
  910.             cr = (*aCtl)->contrlRect;
  911.             slopR = cr;
  912.             InsetRect( &slopR, -32, -32 );
  913.             
  914.             if ( hitIsVertical )
  915.             {
  916.                 cr.top += kWidthOfScrollArrow;
  917.                 cr.bottom -= kWidthOfScrollArrow;
  918.             }
  919.             else
  920.             {
  921.                 cr.left += kWidthOfScrollArrow;
  922.                 cr.right -= kWidthOfScrollArrow;
  923.             }
  924.             
  925.             cRange = GetControlMaximum( aCtl ) - GetControlMinimum( aCtl );
  926.             
  927.             while ( StillDown())
  928.             {
  929.                 GetMouse( &curMouse );
  930.                 
  931.                 if ( DeltaPoint( curMouse, lastMouse ))
  932.                 {
  933.                     lastMouse = curMouse;
  934.                     
  935.                     // calculate value based on mouse location
  936.                     
  937.                     if ( PtInRect( curMouse, &slopR ))
  938.                     {
  939.                         if ( hitIsVertical )
  940.                             cVal = ((long)( curMouse.v - cr.top ) * cRange ) / (long)( cr.bottom - cr.top );
  941.                         else
  942.                             cVal = ((long)( curMouse.h - cr.left ) * cRange ) / (long)( cr.right - cr.left );
  943.                         
  944.                         SetControlValue( aCtl, GetControlMinimum( aCtl ) + cVal );
  945.                     }
  946.                     else
  947.                         SetControlValue( aCtl, cInitValue );        // "spring" back...
  948.                         
  949.                     curValue -= GetControlValue( aCtl );
  950.                     
  951.                     ClipRect( &content );
  952.                     
  953.                     if ( hitIsVertical )
  954.                         Scroll( 0, curValue );
  955.                     else
  956.                         Scroll( curValue, 0 );
  957.                         
  958.                     SetClip( saveClip );
  959.                     curValue = GetControlValue( aCtl );
  960.                 }
  961.             }
  962.             
  963.             // the control manager will attempt to draw the thumb at this point. We'd rather it didn't
  964.             // since we've already moved it. Thus we empty the clip region. A hack, but it works...
  965.             
  966.             SetRect( &cr, 0, 0, 0, 0 );
  967.             ClipRect( &cr );
  968.             
  969.             #endif
  970.             break;
  971.     }
  972.     
  973.     if ( partCode != kControlIndicatorPart )
  974.     {
  975.         curValue -= GetControlValue( aCtl );
  976.         
  977.         ClipRect( &content );
  978.         
  979.         if ( hitIsVertical )
  980.             Scroll( 0, curValue );
  981.         else
  982.             Scroll( curValue, 0 );
  983.             
  984.         SetClip( saveClip );
  985.     }
  986.     DisposeRgn( saveClip );
  987. }
  988.  
  989.  
  990. /*-------------------------------***  WRITETOSTREAM  ***--------------------------------*/
  991. /*
  992. write scroll window data to stream    
  993. ----------------------------------------------------------------------------------------*/
  994.  
  995. void    ZScroller::WriteToStream( ZStream* aStream )
  996. {
  997. #if _MACZOOP_STREAMS
  998.     ZWindow::WriteToStream( aStream );
  999.     
  1000.     aStream->WriteChar( hasHBar );
  1001.     aStream->WriteChar( hasVBar );
  1002.     aStream->WriteRect( &bounds );
  1003.     aStream->WriteShort( hScale );
  1004.     aStream->WriteShort( vScale );
  1005. #endif
  1006. }
  1007.  
  1008.  
  1009. /*------------------------------***  READFROMSTREAM  ***--------------------------------*/
  1010. /*
  1011. read scroll window data from stream    
  1012. ----------------------------------------------------------------------------------------*/
  1013.  
  1014. void    ZScroller::ReadFromStream( ZStream* aStream )
  1015. {
  1016. #if _MACZOOP_STREAMS
  1017.     ZWindow::ReadFromStream( aStream );
  1018.     
  1019.     aStream->ReadChar((char*) &hasHBar );
  1020.     aStream->ReadChar((char*) &hasVBar );
  1021.     aStream->ReadRect( &bounds );
  1022.     aStream->ReadShort( &hScale );
  1023.     aStream->ReadShort( &vScale );
  1024.     
  1025.     MakeScrollbars();
  1026.     CalculateControlParams();
  1027. #endif
  1028. }
  1029.  
  1030.  
  1031.  
  1032.  
  1033.  
  1034. #pragma mark -
  1035.  
  1036.  
  1037.  
  1038. static pascal void    ScrollBarZProc( ControlHandle theControl, short partCode )
  1039. {
  1040.     // action proc for passing scrolling callbacks back to the object.
  1041.     
  1042.     ZScroller*    aScroller = (ZScroller*) GetControlReference( theControl );
  1043.     
  1044.     if ( aScroller )
  1045.         aScroller->ScrollHandler( theControl, partCode );
  1046. }
  1047.  
  1048.  
  1049. #ifdef _LIVE_SCROLLING
  1050.  
  1051. static pascal void    ThumbZProc()
  1052. {
  1053.     if ( gCurrentScrollbar )
  1054.     {
  1055.         ZScroller*    zs = ( ZScroller*) GetControlReference( gCurrentScrollbar );
  1056.         
  1057.         if ( zs )
  1058.             zs->ScrollHandler( gCurrentScrollbar, kControlIndicatorPart );
  1059.     }
  1060. }
  1061.  
  1062. #endif
  1063.